L'anàlisi de registres és una funció important per al control i l'alerta, el compliment de les polítiques de seguretat, l'auditoria i el compliment normatiu, la resposta a incidents de seguretat i fins i tot les investigacions forenses. En analitzar les dades de registre, les empreses poden identificar més fàcilment les possibles amenaces i altres problemes, trobar la causa arrel i iniciar una resposta ràpida per mitigar els riscos.
L'analista ha d'assegurar-se que els registres consisteixen en una gamma completa de missatges i s'interpreten segons el context. Els elements de registre han de normalitzar-se, utilitzant els mateixos termes o terminologia, per evitar confusions i proporcionar cohesió.
Com Científic de Dades se t'ha proporcionat accés als registres-Logs on queda registrada l'activitat de totes les visites a realitzades a la pàgina web de l'agència de viatges "akumenius.com".
exemple: www.akumenius.com 66.249.76.216 - - [23/Feb/2014:03:10:31 +0100] "GET /hoteles-baratos/ofertas-hotel-Club-&-Hotel-Letoonia--en-Fethiye-8460b-destinos.html HTTP/1.1" 404 3100 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" VLOG=-
Fem una ullada al que significa cada camp:
www.akumenius.com :url
66.249.76.216 : adrça IP del client (remote host)
- : espai reservat per la identitat del client, com no està disponible rebem un guionet.
- : espai reservat per la identitat del client un cop idenficcat . Si el document no està protegit amb contrasenya, ens apareix un guionet com es el nostre cas.
[23/Feb/2014:03:10:31 +0100] : és el camp de temps. Cal destacar que aquest format conté un últim camp de 4 digits precedit per un signe de suma o resta que ens indica la zona horària.
"GET (...)" : Linea de petició del client. Aquí ens mostra quin metode ha emprat el client, el mitjà i el seu protocol HTTP.
404 : Un número de 3 digits que ens dóna informació sobre el tipus de resultat que ha aconseguit el client, si ha tingut un resusltat satisfactori, si s'ha redireccionat o si per contra ha donat error.
3100: Un número que ens indica la mida de l'objecte retornat al client.
- : El següent camo és el Referer, que no està disponible.
i per últim,
"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" : La capçalera del User-Agent , que ens serveix per identificar la informació que el cercador client ens ofereix d'ell mateix.
Un cop fet això, comencem a tractar les dades.
#canviarem el q té ara per un espai
\s
# als camps entre " " cometes.
(?=(?:[^"]*"[^"]*")*[^"]*$)
#als camps entre [] claudators.
(?![^\[]*\])
#importem les llibreries que necessitarem:
from datetime import datetime
import pytz
import pandas as pd
import re
import numpy as np
import geoip2.database
import matplotlib.pyplot as plt
# definim un parell de funcions que ens parsejaran el format dels str i el temps per obtenir el maxim d'informació.
def parse_str(x):
return x[1:-1]
def parse_datetime(x):
dt = datetime.strptime(x[1:-7], '%d/%b/%Y:%H:%M:%S')
dt_tz = int(x[-6:-3])*60+int(x[-3:-1])
return dt.replace(tzinfo=pytz.FixedOffset(dt_tz))
df = pd.read_csv(
'Web_access_log-akumenius.com.txt',
sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])',
engine='python',
na_values='-',
header=None,
usecols=[1, 4, 5, 6, 7, 8, 9],
names=['ip', 'time', 'request', 'status', 'size', 'referer', 'user_agent'],
converters={'time': parse_datetime,
'request': parse_str,
'status': int,
'size': int,
'referer': parse_str,
'user_agent': parse_str,})
df.tail()
| ip | time | request | status | size | referer | user_agent | |
|---|---|---|---|---|---|---|---|
| 261868 | 5.255.253.53 | 2014-03-02 03:05:39+01:00 | GET / HTTP/1.1 | 200 | 7528 | NaN | Mozilla/5.0 (compatible; YandexBot/3.0; +http:... |
| 261869 | 74.86.158.107 | 2014-03-02 03:09:52+01:00 | HEAD / HTTP/1.1 | 200 | NaN | NaN | Mozilla/5.0+(compatible; UptimeRobot/2.0; http... |
| 261870 | 127.0.0.1 | 2014-03-02 03:10:18+01:00 | OPTIONS * HTTP/1.0 | 200 | NaN | NaN | Apache (internal dummy connection) |
| 261871 | 127.0.0.1 | 2014-03-02 03:10:18+01:00 | OPTIONS * HTTP/1.0 | 200 | NaN | NaN | Apache (internal dummy connection) |
| 261872 | 127.0.0.1 | 2014-03-02 03:10:18+01:00 | OPTIONS * HTTP/1.0 | 200 | NaN | NaN | Apache (internal dummy connection) |
Ara que ja tinc les dades endreçades i normalitzades
Abans d'afegir les dades de longitud, latitud i Pais que necesitarem més endevant, he de crear les columnes.Després de moltes proves he trobat que és la forma que em funciona
df['pais'] =df['ip']
df['longitud'] =df['ip']
df['latitud'] =df['ip']
Una altre fet rellevant, la IP 127.0.0.1 que correspon al local host, dóna errades en el procésde geolocalització, per això he creat un nou DataFrame que no conté aquests valors.
df2 =df[~(df['ip'].str.contains('127.0.0.1'))]
Per tal de poder Geolocalitzar les IP obrirem la base de dades de mmdb i crearem el reader tal com ens recomanen. Mitjançant una funció lambda i el metode apply, executo els metodes reader.city().country.iso_code, reader.city().location.longitude, reader.city().location.latitude, que ens afegiran ala taula les dades que necessitem.
Aquest modul/database ens permet obtenir molta més informació, arribant fins al Codi Postal, però per aquest exercici no ens aporta valor.
Els dos proper moduls de codi donen error pq estic treballant amb un DtaFrame tallat d'un altre, però com ens dóna un bon resultat, de moment, ho deixaré així.
reader = geoip2.database.Reader('GeoLite2-City.mmdb')
df2['pais']=df2['pais'].apply(lambda x:reader.city(x).country.iso_code)
<ipython-input-8-d641c5b0e9d6>:3: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df2['pais']=df2['pais'].apply(lambda x:reader.city(x).country.iso_code)
df2['longitud']=df2['longitud'].apply(lambda x:reader.city(x).location.longitude)
df2['latitud']=df2['latitud'].apply(lambda x:reader.city(x).location.latitude)
<ipython-input-9-d539be7caf35>:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df2['longitud']=df2['longitud'].apply(lambda x:reader.city(x).location.longitude) <ipython-input-9-d539be7caf35>:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy df2['latitud']=df2['latitud'].apply(lambda x:reader.city(x).location.latitude)
df2.head(5)
| ip | time | request | status | size | referer | user_agent | pais | longitud | latitud | |
|---|---|---|---|---|---|---|---|---|---|---|
| 22 | 66.249.76.216 | 2014-02-23 03:10:31+01:00 | GET /hoteles-baratos/ofertas-hotel-Club-&-Hote... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 |
| 23 | 66.249.76.216 | 2014-02-23 03:10:33+01:00 | GET /hoteles-baratos/ofertas-hotel-Metropolis-... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 |
| 24 | 66.249.76.216 | 2014-02-23 03:10:35+01:00 | GET /hoteles-baratos/ofertas-hotel-Faena-Hotel... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 |
| 25 | 66.249.76.216 | 2014-02-23 03:10:38+01:00 | GET /hoteles-baratos/ofertas-hotel-Kensington-... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 |
| 26 | 66.249.76.216 | 2014-02-23 03:10:39+01:00 | GET /destinos-baratos/destinosEstrelles/hotele... | 200 | 8811 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 |
El següent pas, per poder visualitzar les dades, és importar les llibreries que ens permetran fer els gràficsi mapes.
import geopandas
import folium
import matplotlib.pyplot as plt
import descartes
from shapely.geometry import Point
amb GeoPandas, i la longitud i latitud generem la geometria necessària.
gdf = geopandas.GeoDataFrame(
df2, geometry=geopandas.points_from_xy(df2.longitud, df2.latitud))
gdf.head(5)
| ip | time | request | status | size | referer | user_agent | pais | longitud | latitud | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 22 | 66.249.76.216 | 2014-02-23 03:10:31+01:00 | GET /hoteles-baratos/ofertas-hotel-Club-&-Hote... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 | POINT (-97.82200 37.75100) |
| 23 | 66.249.76.216 | 2014-02-23 03:10:33+01:00 | GET /hoteles-baratos/ofertas-hotel-Metropolis-... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 | POINT (-97.82200 37.75100) |
| 24 | 66.249.76.216 | 2014-02-23 03:10:35+01:00 | GET /hoteles-baratos/ofertas-hotel-Faena-Hotel... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 | POINT (-97.82200 37.75100) |
| 25 | 66.249.76.216 | 2014-02-23 03:10:38+01:00 | GET /hoteles-baratos/ofertas-hotel-Kensington-... | 404 | 3100 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 | POINT (-97.82200 37.75100) |
| 26 | 66.249.76.216 | 2014-02-23 03:10:39+01:00 | GET /destinos-baratos/destinosEstrelles/hotele... | 200 | 8811 | NaN | Mozilla/5.0 (compatible; Googlebot/2.1; +http:... | US | -97.822 | 37.751 | POINT (-97.82200 37.75100) |
I finalment, gràcies a folium, n'obtenim un mapa ambm heatmap, que ens mostra la ubicació dels ip del log inicial.
from folium import plugins
map = folium.Map(location = [15,30], tiles='Cartodb dark_matter', zoom_start = 2)
heat_data = [[point.xy[1][0], point.xy[0][0]] for point in gdf.geometry ]
heat_data
plugins.HeatMap(heat_data).add_to(map)
map